import router from '@/router'
import axios from 'axios'
import qs from 'qs'
import store from '@/store'
import { validatenull } from '@/libs/validate'

import util from '@/libs/util'

import { Loading } from 'element-ui'
// import { Loading, Notification } from 'element-ui'
// import NProgress from 'nprogress' // progress bar
// import 'nprogress/nprogress.css'
// import {basicApi} from '@/config/env' // progress bar style

// 创建一个错误
function errorCreat(response) {
	const msg = response.message
	const error = new Error(msg)
	errorLog(error, response)
	throw error
}

// 记录和显示错误
function errorLog(error, response) {
	console.log('error', error)
	console.log('response', response)
	// const randomId = util.randomLenNum(10)
	if (router.currentRoute.path === '/login') {
		// const tempMsg = `<strong>${error.message}</strong>`
		// Notification({
		// 	type: 'warning',
		// 	title: '异常警告',
		// 	dangerouslyUseHTMLString: true,
		// 	message: tempMsg,
		// 	duration: 2000
		// })
	} else {
		// 添加到日志
		// store.dispatch('d2admin/log/push', {
		// 	message: '异常警告',
		// 	type: 'warning',
		// 	meta: Object.assign(error, { id: randomId }, response)
		// })
		// 打印到控制台
		if (process.env.NODE_ENV === 'development') {
			util.log.danger('>>>>>> Error >>>>>>')
		}
		// const tempMsg = `<strong>${error.message}</strong>`
		// // const tempMsg = `<strong>${error.message}</strong><br><section class="detail-btn">查看详情</section>`
		// Notification({
		// 	type: 'warning',
		// 	title: '异常警告',
		// 	dangerouslyUseHTMLString: true,
		// 	message: tempMsg,
		// 	duration: process.env.NODE_ENV !== 'production' ? 2000 : 0,
		// 	onClick: () => {
		// 		// store.dispatch('d2admin/log/showLogVisible', {
		// 		// 	flag: true
		// 		// })
		// 		// store.dispatch('d2admin/log/setCurrentLogId', {
		// 		// 	id: randomId
		// 		// })
		// 	},
		// 	onClose: () => {
		// 	}
		// })
	}
}

function findStringIndex(string, chart, num) {
	let x = string.indexOf(chart)
	for (let i = 0; i < num; i++) {
		x = string.indexOf(chart, x + 1)
	}
	return x
}

/**
 * @Description: 各种错误，强行退出系统
 * @date 2019/04/24 11:36:47
 * @author jing.fu@topevery.club
 */
function exitProgram(title, msg, isExit = true) {
  setTimeout(() => {
    // Notification({
    //   type: 'error',
    //   title: title || '数据请求异常',
    //   dangerouslyUseHTMLString: true,
    //   message: msg,
    //   duration: process.env.NODE_ENV !== 'production' ? (router.currentRoute.path === '/login' ? 2000 : 0) : 2000
    // })
  }, 0)
	// Notification({
	// 	type: 'error',
	// 	title: title || '数据请求异常',
	// 	dangerouslyUseHTMLString: true,
	// 	message: msg,
	// 	duration: process.env.NODE_ENV !== 'production' ? (router.currentRoute.path === '/login' ? 2000 : 0) : 2000
	// })
	// if (isExit) store.dispatch('d2admin/account/exitProgram', { vm: router.app }, { root: true })
	// if (isExit) store.dispatch('modules/account/exitProgram', { vm: router.app }, { root: true })
}

// 超时时间
axios.defaults.timeout = 30000
// 跨域请求，允许保存cookie
axios.defaults.withCredentials = true
// 基础路径
axios.defaults.baseURL = process.env.VUE_APP_API
// NProgress.configure({ showSpinner: false })// NProgress Configuration
const targets = ['geoserver', 'mongodb']
// const CancelToken = axios.CancelToken
// const source = CancelToken.source()

axios.interceptors.request.use(config => {
		/**
		 * @author jing.fu@topevery.club
		 * @date 2019/04/23 17:15:45
		 * @Description: 处理指定的请求URL
		 */
		const uri = config.url
		const chartIndex = findStringIndex(uri, '/', 1) // 找到'/'第二次出现的下标
		const uri_Prefix = uri.substring(1, chartIndex)
		const uri_Suffix = uri.substring(chartIndex)
		const api_url = process.env.VUE_APP_API
		console.log('process.env', process.env)
		switch (uri_Prefix) {
			// 工作流
			case 'flowApi': {
				if (process.env.NODE_ENV === 'production') {
					const config_uri = `${api_url}${uri_Prefix}/activity${uri_Suffix}`
					config.url = config_uri
				}
				break
			}
		}
		// 开发环境下打开请求输出
		// if (process.env.NODE_ENV !== 'production') console.log(config)
		// NProgress.start() // start progress bar
		/**
		 * 判断是否由登录页发起的网路请求
		 * 比如登录请求，那么直接过滤登录验证
		 */
		if (router.currentRoute.path === '/login') return config
		// if (router.currentRoute.path === '/login' || router.currentRoute.path === '/index2') return config
		/**
		 * 当access_token为空的时候，则说明没有登录，那么请求不能继续
		 * 那么就直接跳到登录页
		 */
		// if (validatenull(store.getters['modules/token/access_token'])) {
		// 	router.push({
		// 		path: '/login'
		// 	})
		// 	// NProgress.done()
		// }

		/**
		 * @author jing.fu@topevery.club
		 * @date 2019/04/23 17:11:25
		 * @Description: 过滤掉 geoserver 的请求
		 */
		const target = config.headers.target
		if (!validatenull(target) && targets.includes(target)) {
			config.headers = Object.assign({}, config.headers, {
				'Access-Control-Allow-Origin': '*'
			})
			return config
		}
		config.headers = Object.assign({}, config.headers, {
			'Authorization': `Bearer ${store.getters['modules/token/access_token']}`
			// 'Authorization': `Bearer 31ebec01-c035-44c4-bfe9-5c2b623a70d6`
		})
		return config
	},
	error => {
		return Promise.reject(error)
	})

// 响应拦截器
axios.interceptors.response.use(response => {
		// NProgress.done()
		console.log('response======>', response) // 开发环境下打开请求输出
		// dataAxios 是 axios 返回数据中的 data
		const status = response.status
		const res = response.data
		// 这个状态码是和后端约定的
		const { code, success } = res
		// 根据 code 进行判断
		if (status === undefined) {
			// 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本
			errorCreat({ message: '此接口非图元开发接口' })
			return Promise.reject(response)
		} else {
			// 有 code 代表这是一个后端接口 可以进行进一步的判断
			switch (status) {
				case 200: {
					if (code === 200 && success) {
						res.enable = response.headers['page-enable']
						if (res.enable) {
							res.limit = Number.parseInt(response.headers['page-limit'])
							res.current = Number.parseInt(response.headers['page-current'])
							res.total = Number.parseInt(response.headers['page-total'])
							res.count = Number.parseInt(response.headers['count'])
						}
						return res
					} else {
						/**
						 * @author jing.fu@topevery.club
						 * @date 2019/04/24 11:27:23
						 * @Description: 请求成功，status=200,但是接口返回code ！=200
						 */
						switch (code) {
							case 401: {
								exitProgram('用户信息已过期', 'Token为空，请重新登录')
								return
							}
							case 1000: {
								exitProgram('用户登陆失败', res.message, false)
								return
							}
							default: {
								const url = response.config.url
								if (url.includes('filesApi') || url.includes('oauth') || url.includes('geoServerApi')) {
									return response
								}
								const target = response.config.headers.target
								if (!validatenull(target) && targets.includes(target)) {
									return response
								}

								// if (response.config.url === `${axios.defaults.baseURL}${basicApi}/user/userExport`) {
								// 	return response
								// }
								errorCreat(Object.assign({}, res, { apiUrl: response.config.url }))
								return Promise.reject(response)
							}
						}
					}
				}
				case 400: {
					exitProgram('错误', res.message, false)
					return
				}
				case 401: {
					exitProgram('用户信息已过期', '请重新登录！')
					return
				}
				case 404: {
					exitProgram('错误', res.message, false)
					return
				}
				case 405: {
					exitProgram('错误', res.message, false)
					return
				}
				default: {
					errorCreat(Object.assign({}, res, { apiUrl: response.config.url }))
					return Promise.reject(response)
				}
			}
		}
	},
	error => {
		if (process.env.NODE_ENV !== 'production') console.log(error) // 开发环境下打开响应异常输出
		// NProgress.done()
		if (error && error.response) {
			switch (error.response.status) {
				case 400:
					error.message = '访问资源不存在'
					break
				case 401:
					switch (error.response.data.code) {
						case 401:
							if (!validatenull(store.getters['modules/token/access_token'])) {
								exitProgram('用户信息已过期', '请重新登录！')
							} else {
								exitProgram('用户登陆失败', error.response.data.message)
							}
              exitProgram('用户信息已过期', error.response.data.message, false)
              break
						case 1000:
							exitProgram('用户登陆失败', error.response.data.message, false)
							break
						case 1001:
							exitProgram('用户登陆失败', error.response.data.message, false)
							break
					}
					return
				case 403:
					error.message = '请求拒绝访问'
					break
				case 404:
					error.message = '访问资源不存在'
					break
				case 405:
					error.message = error.response.data.message
					break
				case 406:
					error.message = '请求的格式不正确'
					break
				case 410:
					error.message = '数据被删除'
					break
				case 415:
					error.message = '不支持的媒体类型'
					break
				case 422:
					error.message = error.response.data.message // 参数验证错误
					break
				case 428:
					error.message = '验证码错误'
					break
				case 408:
					error.message = '请求超时'
					break
				case 500:
					error.message = '服务器内部错误'
					break
				case 501:
					error.message = '服务未实现'
					break
				case 502:
					error.message = '网关错误'
					break
				case 503:
					error.message = '服务不可用'
					break
				case 504:
					error.message = '网关超时'
					break
				case 505:
					error.message = 'HTTP版本不受支持'
					break
				default:
					break
			}
		}
		errorLog(error, Object.assign({}, error.response, { apiUrl: error.response.config.url, message: error.message }))
		return Promise.reject(error)
	})

const http = {
	axios
}

/**
 * @author jing.fu@topevery.club
 * @date 2018/11/21 13:52:34
 * @Description: 封装统一的GET请求方法
 */
http.$GET = function(url, options, header = {}, showLoading = false, timeout = 800) {
	// 此处可以给GET请求整合一些公共的请求参数
	const params = Object.assign({}, options)
	let loadingInstance = null
	// 请求时的友好提示，如不需要可以直接注释
	if (showLoading) {
		loadingInstance = Loading.service({
			fullscreen: true,
			lock: true,
			text: '请稍候',
			background: 'rgba(0, 0, 0, 0.7)'
		})
	}

	return new Promise((resolve, reject) => {
		setTimeout(() => {
			axios.get(url, {
				headers: header,
				params: params
			})
				.then(response => {
					if (loadingInstance !== null) {
						loadingInstance.close()
					}
					resolve(response)
				})
				.catch(error => {
					if (loadingInstance !== null) {
						loadingInstance.close()
					}
					reject(error)
				})
		}, timeout)
	})
}

/**
 * @author jing.fu@topevery.club
 * @date 2018/11/21 14:02:39
 * @Description: 封装统一的PATCH请求方法
 * @param: url
 * @param: options 参数
 * @param: isParams 是否已参数的形式传值
 * @param: header header参数
 */
http.$PATCH = function(url, options, isParams = false, header = {}, showLoading = false, timeout = 0) {
	// 此处可以给PATCH请求整合一些公共的请求参数
	const data = Object.assign({}, options)
	let loadingInstance = null
	// 请求时的友好提示，如不需要可以直接注释
	if (showLoading) {
		loadingInstance = Loading.service({
			fullscreen: true,
			lock: true,
			text: '请稍候',
			background: 'rgba(0, 0, 0, 0.7)'
		})
	}

	return new Promise((resolve, reject) => {
		setTimeout(() => {
			if (isParams) {
				axios.patch(url, {}, {
					headers: header,
					params: data
				})
					.then(response => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						resolve(response)
					})
					.catch(error => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						reject(error)
					})
			} else {
				axios.patch(url, data, {
					headers: header
				})
					.then(response => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						resolve(response)
					})
					.catch(error => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						reject(error)
					})
			}
		}, timeout)
	})
}

/**
 * @author jing.fu@topevery.club
 * @date 2018/11/21 14:46:40
 * @Description: 封装统一的POST请求方法
 * @param: url
 * @param: options 参数
 * @param: isParams 是否已参数的形式传值
 * @param: header header参数
 * @param: identifying 参数只针对登录页login接口把对象通过QS插件转Form表单方式提交给后端
 */
http.$POST = function(url, options, isParams = false, header = {}, showLoading = false, timeout = 0, identifying = true) {
	// 此处可以给POST请求整合一些公共的请求参数
	const data = Object.assign({}, options)
	let loadingInstance = null
	// 请求时的友好提示，如不需要可以直接注释
	if (showLoading) {
		loadingInstance = Loading.service({
			fullscreen: true,
			lock: true,
			text: '请稍候',
			background: 'rgba(0, 0, 0, 0.7)'
		})
	}

	return new Promise((resolve, reject) => {
		setTimeout(() => {
			if (isParams) {
				axios.post(url, {}, {
					headers: header,
					params: data
				})
					.then(response => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						resolve(response)
					})
					.catch(error => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						reject(error)
					})
			} else {
				if (identifying) {
					axios.post(url, data, {
						headers: header
					})
						.then(response => {
							if (loadingInstance !== null) {
								loadingInstance.close()
							}
							resolve(response)
						})
						.catch(error => {
							if (loadingInstance !== null) {
								loadingInstance.close()
							}
							reject(error)
						})
				} else {
					axios.post(url, qs.stringify(options), {
						headers: header
					})
						.then(response => {
							if (loadingInstance !== null) {
								loadingInstance.close()
							}
							resolve(response)
						})
						.catch(error => {
							if (loadingInstance !== null) {
								loadingInstance.close()
							}
							reject(error)
						})
				}
			}
		}, timeout)
	})
}

/**
 * @author jing.fu@topevery.club
 * @date 2018/11/21 14:48:18
 * @Description: 封装统一的PUT请求方法
 * @param: url
 * @param: options 参数
 * @param: isParams 是否已参数的形式传值
 * @param: header header参数
 */
http.$PUT = function(url, options, isParams = false, header = {}, showLoading = false, timeout = 0) {
	// 此处可以给PUT请求整合一些公共的请求参数
	const data = Object.assign({}, options)
	let loadingInstance = null
	// 请求时的友好提示，如不需要可以直接注释
	if (showLoading) {
		loadingInstance = Loading.service({
			fullscreen: true,
			lock: true,
			text: '请稍候',
			background: 'rgba(0, 0, 0, 0.7)'
		})
	}

	return new Promise((resolve, reject) => {
		setTimeout(() => {
			if (isParams) {
				axios.put(url, {}, {
					headers: header,
					params: data
				})
					.then(response => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						resolve(response)
					})
					.catch(error => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						reject(error)
					})
			} else {
				axios.put(url, data, {
					headers: header
				})
					.then(response => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						resolve(response)
					})
					.catch(error => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						reject(error)
					})
			}
		}, timeout)
	})
}

/**
 * @author jing.fu@topevery.club
 * @date 2018/11/21 14:49:41
 * @Description: 封装统一的DELETE请求方法
 * @param: isData 是否以对象的形式传值
 * @param: header header参数
 */
http.$DELETE = function(url, options, isData = false, header = {}, showLoading = false, timeout = 0) {
	// 此处可以给DELETE请求整合一些公共的请求参数
	const params = Object.assign({}, options)
	let loadingInstance = null
	// 请求时的友好提示，如不需要可以直接注释
	if (showLoading) {
		loadingInstance = Loading.service({
			fullscreen: true,
			lock: true,
			text: '请稍候',
			background: 'rgba(0, 0, 0, 0.7)'
		})
	}

	return new Promise((resolve, reject) => {
		setTimeout(() => {
			if (isData) {
				axios.delete(url, {
					headers: header,
					data: params
				})
					.then(response => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						resolve(response)
					})
					.catch(error => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						reject(error)
					})
			} else {
				axios.delete(url, {
					headers: header,
					params: params
				})
					.then(response => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						resolve(response)
					})
					.catch(error => {
						if (loadingInstance !== null) {
							loadingInstance.close()
						}
						reject(error)
					})
			}
		}, timeout)
	})
}

export default http
